package com.xbongbong.saas.factory.publicrule;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ClueUserEntity;
import com.xbongbong.saas.domain.entity.RuleClueEntity;
import com.xbongbong.saas.domain.entity.ext.ClueEntityExt;
import com.xbongbong.saas.enums.ClueRuleChildEnum;
import com.xbongbong.saas.enums.ClueRuleEnum;
import com.xbongbong.saas.enums.business.ClueEnum;
import com.xbongbong.saas.model.ClueUserModel;
import com.xbongbong.sys.domain.entity.UserEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;


/**
 * @author long
 * @version v1.0
 * @date 2020/12/1 14:49
 * @since v1.0
 */
public abstract class AbstractCheckClueRule {

    private static final Logger LOG = LoggerFactory.getLogger(AbstractCheckClueRule.class);
    @Resource
    protected ClueUserModel clueUserModel;
    @Resource
    protected XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;

    /**
     * @Description: 移除规则中不需要退回公海池的线索
     * @param clueList 线索列表
     * @param typeNotIn 需要移除的线索状态
     */
    public void removeRuleNoBack(List<RuleClueEntity> clueList, List<String> typeNotIn) {
        List<Long> clueIdIn = new ArrayList<>();
        clueIdIn.add(-1L);
        //移除被规则排除的线索状态
        if(typeNotIn != null){
            Iterator<RuleClueEntity> it = clueList.iterator();
            while(it.hasNext()) {
                RuleClueEntity clue = it.next();
                String type = "";
                Integer typeInt = clue.getType();
                if (typeInt != null) {
                    type = clue.getType().toString();
                }
                if(typeNotIn.contains(type)){
                    it.remove();
                }else{
                    clueIdIn.add(clue.getId());
                }
            }
        }
    }

    /**
     * @Description: 根据标签移除规则中不需要退回公海池的线索
     * @param clueList 线索列表
     * @param labelNotIn 需要移除的线索标签
     */
    public void removeRuleLabelNoBack(List<RuleClueEntity> clueList, List<Long> labelNotIn) {
        List<Long> clueIdIn = new ArrayList<>();
        clueIdIn.add(-1L);
        //移除被规则排除的线索标签
        if(CollectionsUtil.isEmpty(labelNotIn)){
            return;
        }
        Iterator<RuleClueEntity> it = clueList.iterator();
        while(it.hasNext()) {
            RuleClueEntity clue = it.next();
            String labels = clue.getLabels();
            if (StringUtil.isEmpty(labels) && "null".equals(labels)) {
                continue;
            }
            List<Long> labelIds = null;
            try {
                labelIds = JSONArray.parseArray(labels, Long.class);
            }catch (Exception e){
                LOG.error("removeRuleLabelNoBack: 线索标签转换错误",e);
                continue;
            }
            if(labelIds==null){
                continue;
            }
            labelIds.retainAll(labelNotIn);
            if(CollectionsUtil.isNotEmpty(labelIds)){
                it.remove();
            }else{
                clueIdIn.add(clue.getId());
            }
        }
    }

    /**
     * @Description: 获取  线索id：ClueUserEntity的一个map
     * @param corpid 公司id
     * @param userId 线索所属的员工id
     * @param clueList 员工所属的线索id
     * @return
     */
    public Map<Long, ClueUserEntity> getClueUserMap(String corpid, String userId, List<RuleClueEntity> clueList){

        List<Long> clueIdIn = new ArrayList<>();
        for(RuleClueEntity clue : clueList){
            clueIdIn.add(clue.getId());
        }
        clueIdIn.add(-1L);

        //获取线索分配时间 tb_clue_user表结构没有改变
        Map<String,Object> clueUserParam = new HashMap<>(6);
        clueUserParam.put("dataIdIn", clueIdIn);
        clueUserParam.put("corpid", corpid);
        clueUserParam.put("userId", userId);
        clueUserParam.put("isMain", 1);
        clueUserParam.put("del", 0);
        clueUserParam.put("orderByStr","distribution_time desc");
        List<ClueUserEntity> list = clueUserModel.findEntitys(clueUserParam);

        Map<Long, ClueUserEntity> retMap = new HashMap<>(16);
        for(ClueUserEntity clueUser : list){
            retMap.put(clueUser.getDataId(), clueUser);
        }
        return retMap;
    }

    /**
     * @Description: 判断线索分配时间是否超过规则设置的天数
     * @param clueUser 线索员工分配关系
     * @param ruleDay 规则设置的天数
     * @return
     */
    public boolean distributionTimeExceedRuleTime(ClueUserEntity clueUser, Integer ruleDay){

        Long second = ruleDay * 86400L;

        //获取线索分配时间
        Long distributionTime = null;
        if(clueUser != null){
            distributionTime = clueUser.getDistributionTime();
        }

        if(distributionTime!=null){
            //捞取线索的时间在规则时间之内
            if((DateTimeUtil.getInt() - distributionTime) < second){
                return false;
            }
        }else{
            //当分配时间是空的时候也不用处理
            return false;
        }
        return true;
    }

    /**
     * 设置线索退回公海池提醒内容
     * @param clue 线索实体
     * @param userName 线索负责人名
     * @param ruleType 规则类型
     * @param newTime 最新的线索联系时间、(也可能是分配时间)
     * @param day 规则中限制的天数（不算上提前量）
     */
    public void setLeftDay(RuleClueEntity clue, String userName, Integer ruleType, Long newTime, Integer day){
        Long leftDay = 0L;

        Long now = DateTimeUtil.getInt();
        //应该退回的时间
        Long backTime = newTime + (day * 86400L);
        //现在到退回时间的时间间隔
        Long leftTime = backTime - now;
        if(leftTime > 0) {
            //正常提醒
            leftDay = leftTime / TimeConstant.SECONDS_PER_DAY;
            if(leftTime % TimeConstant.SECONDS_PER_DAY > 0) {
                leftDay ++;
            }
        }

        String ruleName = ClueRuleEnum.getByCode(ruleType).getName();
        leftDay = leftDay < 1 ? 1 : leftDay;

        String memo = String.format(I18nMessageUtil.getMessage(StringConstant.PUBLIC_TAG_MEMO), userName, ruleName, leftDay);

        clue.setUserName(userName);
        clue.setRuleName(ruleName);
        clue.setLeftDay(leftDay);
        clue.setNotifyMemo(memo);
    }

    /**
     * 获取code对应的设置
     * @param array
     * @param code
     * @return
     */
    public JSONObject getJsonByCode(JSONArray array, Integer code) {
        for(Object object : array){
            JSONObject json = (JSONObject)object;
            String keyStr = json.getString("key");

            Integer key = StringUtil.toInt(keyStr, null);

            if(Objects.equals(key, code)){
                return json;
            }
        }
        return null;
    }

    /**
     * @Description: 获取最小公海规则配置
     * @param restrictArray 规则设置的数组
     * @param userEntity 设置判断人
     * @param type 公海规则子类型 ClueRuleChildEnum
     * @return
     */
    public JSONObject getMinObject(JSONArray restrictArray, UserEntity userEntity, Integer type){
        JSONObject allObject = new JSONObject();
        JSONObject specialObject = new JSONObject();
        List<Long> deptIds = new ArrayList<>();
        try {
            deptIds = JSONArray.parseArray(userEntity.getDepartment(), Long.class);
        } catch (Exception e) {
            deptIds = new ArrayList<>();
        }
        if (deptIds == null) {
            deptIds = new ArrayList<>();
        }
        List<Integer> roleIds = new ArrayList<>();
        String role = userEntity.getRoleIds();
        if (StringUtil.isNotEmpty(role)) {
            roleIds = StringUtil.roleIdToListInt(role);
        }
        if (roleIds == null) {
            roleIds = new ArrayList<>();
        }
        for(Object restrictObject : restrictArray){
            JSONObject restrictJson = (JSONObject)restrictObject;
            JSONArray users = restrictJson.getJSONArray("users");
            JSONArray depts = restrictJson.getJSONArray("depts");
            JSONArray roles = restrictJson.getJSONArray("roles");
            List<String> userIdList = new ArrayList<>();
            List<Long> deptIdList = new ArrayList<>();
            List<Integer> roleIdList = new ArrayList<>();
            if (Objects.nonNull(users)) {
                userIdList = JSON.parseArray(users.toJSONString(), String.class);
            }
            if (Objects.nonNull(depts)) {
                deptIdList = JSON.parseArray(depts.toJSONString(), Long.class);
            }
            if (Objects.nonNull(roles)) {
                roleIdList = JSON.parseArray(roles.toJSONString(), Integer.class);
            }
            deptIdList.retainAll(deptIds);
            roleIdList.retainAll(roleIds);
            Boolean scecialConfig = users != null || depts != null || roles != null;
            Boolean configFail = !userIdList.contains(userEntity.getUserId()) && deptIdList.isEmpty() && roleIdList.isEmpty();
            if(scecialConfig && configFail){
                //对于当前用户无效的配置
                continue ;
            }

            JSONArray array = restrictJson.getJSONArray("array");

            if (Objects.equals(type, ClueRuleChildEnum.ALL.getCode())) {
                integerKey(array, users, depts, roles, allObject, specialObject);
            } else {
                stringKey(array, users, depts, roles, allObject, specialObject);
            }
        }
        return specialObject.isEmpty() ? allObject : specialObject;
    }

    private void stringKey(JSONArray array, JSONArray users, JSONArray depts, JSONArray roles, JSONObject allObject, JSONObject specialObject) {
        for(Object object : array){
            JSONObject jsonObject = (JSONObject)object;
            String key = jsonObject.getString("key");
            Integer value = jsonObject.getInteger("value");

            if(users == null && depts == null && roles == null){
                allObject.put(key, value);
                continue ;
            }

            //获取所有特殊员工配置的最小值
            Integer minValue = specialObject.getInteger(key);
            //若不存在对应值或值比当前值大，则用当前值覆盖（获取最小值）
            if(minValue == null || minValue > value){
                specialObject.put(key, value);
            }
        }
    }
    private void integerKey(JSONArray array, JSONArray users, JSONArray depts, JSONArray roles, JSONObject allObject, JSONObject specialObject) {
        for(Object object : array){
            JSONObject jsonObject = (JSONObject)object;
            Integer key = jsonObject.getInteger("key");
            Integer value = jsonObject.getInteger("value");

            if(users == null && depts == null && roles == null){
                allObject.put(key+"", value);
                continue ;
            }

            //获取所有特殊员工配置的最小值
            Integer minValue = specialObject.getInteger(key+"");
            //若不存在对应值或值比当前值大，则用当前值覆盖（获取最小值）
            if(minValue == null || minValue > value){
                specialObject.put(key+"", value);
            }
        }
    }

    /**
     * 是否是不需要退回的线索
     * @param clueEntity
     * @param typeNotIn
     * @return
     */
    public boolean notBackClue(ClueEntityExt clueEntity, List<String> typeNotIn) {
        String type = clueEntity.getData().getString(ClueEnum.CLUE_STATUS.getAttr());
        //匹配到线索状态
        if (Objects.nonNull(type) && Objects.nonNull(typeNotIn) && typeNotIn.contains(type)) {
            return true;
        }
        return false;
    }

    /**
     * 是否是不需要退回的线索
     * @param clueEntity
     * @param labelNotIn
     * @return
     */
    public boolean notBackClue4Label(ClueEntityExt clueEntity, List<Long> labelNotIn) {
        JSONArray jsonArray = clueEntity.getData().getJSONArray(ClueEnum.LABEL.getAttr());
        List<Long> labels = null;
        if (CollectionsUtil.isNotEmpty(jsonArray)) {
            labels = JSON.parseArray(jsonArray.toJSONString(), Long.class);
        }
        if (CollectionsUtil.isEmpty(labelNotIn) || CollectionsUtil.isEmpty(labels)) {
            return false;
        }
        labels.retainAll(labelNotIn);
        if (CollectionsUtil.isNotEmpty(labels)) {
            return true;
        }
        return false;
    }
}
